﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "ElementEnums.h"
#include "GcmpApiDeclaration.h"
#include "GcmpModelInterface.h"
#include "IDbObject.h"
#include "JoinPositions.h"
#include "RegenDataId.h"
#include "Vector3d.h"

namespace gcmp {

    class NdbClassSchema;
    class ICalculatorCollection;
    class IDocument;
    class ElementLocatingContext;
    class IElementModelShape;
    class IElementParentReporter;
    class IElementPosition;
    class IExternalData;
    class IGraphicsCurve3d;
    class IGraphicsElementShape;
    class IElementCopyPasteComponent;
    class IElementCopyStrategyComponent;
    class IJoinRelationshipBehavior;
    class ICutRelationshipBehavior;
    class IElementModelingOperations;
    class Matrix4d;
    class IModelView;
    class IParameterBinding;
    class IElementParameterBindings;
    class IType;
    class IGraphicsNodeStyleAndMaterialOverride;

    class IElementParameters;
    class IElementViewSpecificShapeComponent;
    class IElementConstraintBehavior;
    class IPasteHelper;
    class IGraphicsNodeReference;
    class UniIdentity;
    class GraphicsNodeId;
    class ICommandBehavior;
    class IElementBasicInformation;
    class ElementImpl;
    class IElementStatus;

    //无状态行为前置声明
    class IElementDeletionComponent;
    class IElementRegenerationComponent;
    class IElementPositionPoints;
    class IElementJoinBehavior;
    class IElementUiManipulatorComponent;
    class IElementTrimComponent;
    class IElementAlignComponent;
    class IElementOffsetComponent;
    class IElementTransformationComponent;
    class IElementPositionReportComponent;
    class IGeometryRelationshipComponent;
    class IExternalDataComponent;
    class IElementAttributes;
    class IGroupComponent;
    class IElementTags;

    class IOpeningGraphicsElementShapeComponent;
    class IOpenedGraphicsElementShapeComponent;
    class ICutterGraphicsElementShapeComponent;
    class ICutteeGraphicsElementShapeComponent;
    class IOpeningRelationshipBehavior;
    class ICutRelationshipBehavior;

    /// \brief 文档元素基类。
    ///
    /// 文档由一系列文档元素组成。文档元素可以是具体的项目构件如墙、门、窗等，也可以是抽象的概念如视图、元素类型等。
    FINAL_INTERFACE class GCMP_MODEL_INTERFACE_EXPORT IElement : public IDbObject
    {
        DEFINE_CAST_DERIVED(gcmp::IElement, gcmp::IDbObject);

    public:

#pragma region 基本属性

        /// \brief 获得元素基础信息模块 
        /// \return IBasicInformation* 基础信息模块指针
        virtual const IElementBasicInformation* GetBasicInformation() const = 0;

        /// \brief 获得元素基础信息模块
        /// \return IBasicInformation* 基础信息模块指针
        virtual IElementBasicInformation* GetBasicInformation() = 0;

        /// \brief 获得元素所属文档
        /// \return IDocument* 文档指针
        virtual IDocument* GetDocument() const = 0;

        /// \brief 设置元素所属文档
        /// \param pDocument 所属文档
        /// \return void
        virtual void SetDocument(IDocument* pDocument) = 0;
        
        /// \brief 获得元素的Id
        /// \return ElementId 元素的Id
        virtual ElementId GetElementId() const = 0;

        /// \brief 获得宿主元素的Id
        ///
        /// 元素的位置可能依赖于宿主元素;
        /// PointOnCurve2dOnSingleAssociatedPlanePositionBehavior等的定位方式可以体现这一依赖，比如：门在墙上，墙是宿主。
        /// \return 主元素的Id
        virtual ElementId GetHostElementId() const = 0;

        /// \brief 获取该元素的状态集
        ///
        /// 当前包括元素的以下属性： IsVisible、 IsModifiable、CanBeMoved、 CanBeRotated、CanBeOffset
        /// \return IElementStatus* 状态集指针
        virtual IElementStatus* GetStatus() = 0;
        
        /// \brief 获取该元素的状态集
        ///
        /// 当前包括元素的以下属性： IsVisible、 IsModifiable、CanBeMoved、 CanBeRotated、CanBeOffset
        /// \return IElementStatus* 状态集指针
        virtual const IElementStatus* GetStatus() const = 0;

        /// \brief 获取元素所属组或组类型的ElementId
        ///
        /// \return ElementId 组或组类型的ElementId
        virtual ElementId GetGroupId() const = 0;

        /// \brief 设置元素所属组或组类型的ElementId
        /// \param groupId 组或组类型的ElementId
        /// \return 
        virtual void SetGroupId(const ElementId& groupId) = 0;

        /// \brief 设置元素是否在组类型内
        /// \param isInGroupType 元素是否在组类型内
        /// \see IGroupType.h
        virtual void SetIsInGroupType(bool isInGroupType) = 0;

        /// \brief 元素是否在组类型内
        /// \return bool true代表在组类型内，false代表不在组类型内
        /// \see IGroupType.h
        virtual bool IsInGroupType() const = 0;

        /// \brief 获取对象所属的工作单元
        /// \return 所属工作单元。未设置返回nullptr
        virtual const std::wstring * GetOwnerDatasetId() const = 0;

        /// \brief 获取对象所属的工作单元
        /// \return std::set<std::wstring>* 所属工作单元。未设置返回nullptr
        /// \note 如果一个对象属于多个工作单元，该接口会拿到多个工作单元
        virtual const std::set<std::wstring>* GetOwnerAllDatasetId() const = 0;

        /// \brief 设置对象所属的工作单元
        ///
        /// \param datasetId 所属工作单元
        /// \return 是否设置成功
        /// \note 会用datasetId覆盖工作单元，如果希望一个对象属于多个工作单元。需要用另外的接口，暂无。
        virtual bool SetOwnerDatasetId(const std::wstring & datasetId) = 0;

        /// \brief 追加对象所属的工作单元
        ///
        /// \param datasetId 所属工作单元
        /// \return 是否设置成功
        /// \note 如果希望一个对象属于多个工作单元，通过该接口设置。
        virtual bool AppendOwnerDatasetId(const std::wstring & datasetId) = 0;

        /// \brief 使对象不属于某个工作单元
        ///
        /// \param datasetId 工作单元
        /// \return 是否设置成功
        /// \note 如果希望一个对象不属于某个工作单元，通过该接口设置。
        virtual bool RemoveOwnerDatasetId(const std::wstring & datasetId) = 0;

        /// \brief 判断对象是否可用来初始化构件级协同项目
        ///
        /// 创建一个文件，包含平台和产品的部分公共对象，上传生成公共的工作单元，被其他工作单元引用。
        /// \return true-可以；否-不可以
        /// \see IDocument * IDocumentManager::CreateTemplateDocumentToInitializeElementCollaborationProject(IDocumentInitializer *);
        virtual bool IsForInitializeElementCollaborationProject() const = 0;

        /// \brief 设置对象是否可用来初始化构件级协同项目
        ///
        /// \param value 设置的值
        virtual void SetIsForInitializeElementCollaborationProject(bool value) = 0;
#pragma endregion 基本属性

        /// \brief 此接口用于对删掉的弱依赖做适当的处理
        ///
        /// 当弱依赖的Element被删除后，此接口会被调用：
        ///   1.移除引用的Element Id。
        ///   2.将引用的Element Id设成无效值。
        ///   3.选用另外一个有意义的Element作引用。
        /// \param toBeDeletedElementIds 表示将被删除的ElementIds
        /// \return void
        virtual void UpdateForWeakParentDeletion(const std::set<ElementId>& toBeDeletedElementIds) = 0;

        /// \brief 报告依赖的ElementIds
        ///
        /// 元素删除和关联更新依赖于这个接口的正确实现:
        ///   1. 报告强依赖IElement(ElementParentReporter::ReportStrong): 强依赖IElement被删除，此IElement也会自动被系统删除。
        ///   2. 报告弱依赖IElement(ElementParentReporter::ReportWeak)：弱依赖IElement被删除，此IElement会通过UpdateForWeakParentDeletion得到通知。
        /// 依赖ElementIds的来源主要有两个:
        ///   1. IElement属性直接或间接引用的Id。
        ///   2. 用到的全局的ElementId。
        /// \param elementParentReporter Element关系报告器
        /// \return void
        virtual void ReportParents(IElementParentReporter& elementParentReporter) const = 0;

#pragma region 无状态行为接口
        /// \brief 获得Element刪除组件接口
        /// \return IElementDeletionComponent* 获取的Element刪除组件
        /// \see IElementDeletionComponent
        virtual IElementDeletionComponent* GetElementDeletionComponent() = 0;

        /// \brief 获得Element刪除组件接口
        /// \return const IElementDeletionComponent* 获取的Element刪除组件
        /// \see IElementDeletionComponent
        virtual const IElementDeletionComponent* GetElementDeletionComponent() const = 0;

        /// \brief 获得IElementRegenerationComponent
        /// \return IElementRegenerationComponent* 获取的IElementRegenerationComponent
        /// \see IElementRegenerationComponent
        virtual IElementRegenerationComponent* GetElementRegenerationComponent() = 0;

        /// \brief 获得IElementRegenerationComponent
        /// \return const IElementRegenerationComponent* 获取的IElementRegenerationComponent
        /// \see IElementRegenerationComponent
        virtual const IElementRegenerationComponent* GetElementRegenerationComponent() const = 0;

        /// \brief 设置IElementRegenerationComponent
        /// \param opElementRegenerationComponent 关联更新组件 
        /// \return bool 是否设置成功
        /// \see IElementRegenerationComponent
        virtual bool SetElementRegenerationComponent(OwnerPtr<IElementRegenerationComponent> opElementRegenerationComponent) = 0;


        /// \brief 获得IElementPositionPoints
        /// \return IElementPositionPoints* 获取的IElementPositionPoints
        /// \see IElementPositionPoints
        virtual IElementPositionPoints* GetPositionPoints() = 0;

        /// \brief 获得IElementPositionPoints
        /// \return const IElementPositionPoints* 获取的IElementPositionPoints
        /// \see IElementPositionPoints
        virtual const IElementPositionPoints* GetPositionPoints() const = 0;

        /// \brief 设置IElementPositionPoints
        /// \param opPositionPoints 控制点行为
        /// \return void
        virtual void SetPositionPoints(OwnerPtr<IElementPositionPoints> opPositionPoints) = 0;



        /// \brief 获得Element变换组件
        /// \return const IElementTransformationComponent* 获取的Element变换组件
        /// \see IElementTransformationComponent
        virtual IElementTransformationComponent* GetElementTransformationComponent() = 0;

        /// \brief 获得Element变换组件
        /// \return const IElementTransformationComponent* 获取的Element变换组件
        /// \see IElementTransformationComponent
        virtual const IElementTransformationComponent* GetElementTransformationComponent() const = 0;

        /// \brief 设置Element变换组件
        /// \param opElementTransformationComponent 变换组件
        /// \return bool
        virtual bool SetElementTransformationComponent(OwnerPtr<IElementTransformationComponent> opElementTransformationComponent) = 0;

        /// \brief 获得IElementCopyPasteComponent
        /// \return const IElementCopyPasteComponent* 获取的IElementCopyPasteComponent
        /// \see IElementCopyPasteComponent
        virtual IElementCopyPasteComponent* GetCopyPasteComponent() = 0;

        /// \brief 获得IElementCopyPasteComponent
        /// \return const IElementCopyPasteComponent* 获取的IElementCopyPasteComponent
        /// \see IElementCopyPasteComponent
        virtual const IElementCopyPasteComponent* GetCopyPasteComponent() const = 0;

        /// \brief 设置IElementCopyPasteComponent
        /// \param opElementCopyPasteComponent 拷贝粘贴组件
        /// \return bool
        virtual bool SetElementCopyPasteComponent(OwnerPtr<IElementCopyPasteComponent> opElementCopyPasteComponent) = 0;

        /// \brief 设置拷贝策略组件
        /// \param opElementCopyStrategyComponent 拷贝策略组件
        /// \return bool
        virtual bool SetElementCopyStrategyComponent(OwnerPtr<IElementCopyStrategyComponent> opElementCopyStrategyComponent) = 0;

        /// \brief 获得报告拷贝策略组件
        /// \return IElementCopyStrategyComponent * 报告拷贝策略组件
        /// \see IElementCopyStrategyComponent
        virtual IElementCopyStrategyComponent * GetElementCopyStrategyComponent() = 0;

        /// \brief 获得报告拷贝策略组件
        /// \return const IElementCopyStrategyComponent * 报告拷贝策略组件
        /// \see IElementCopyStrategyComponent
        virtual const IElementCopyStrategyComponent * GetElementCopyStrategyComponent() const = 0;

        /// \brief 获得位置报告组件
        /// 
        /// 例如：定位对象（如标高、工作平面等），需要报告自身的位置（如坐标系、高度等）
        /// \return  IElementPositionReportComponent * 位置报告组件
        virtual IElementPositionReportComponent * GetElementPositionReportComponent() = 0;

        /// \brief 获得位置报告组件
        /// 
        /// 例如：定位对象（如标高、工作平面等），需要报告自身的位置（如坐标系、高度等）
        /// \return  IElementPositionReportComponent * 位置报告组件
        virtual const IElementPositionReportComponent * GetElementPositionReportComponent() const = 0;

#pragma endregion 无状态行为接口

#pragma region 定位
        /// \brief 获得定位行为接口
        /// \return const IElementPosition* 定位行为接口
        virtual const IElementPosition* GetElementPosition() const = 0;

        /// \brief 获得定位行为接口
        /// \return IElementPosition* 定位行为接口
        virtual IElementPosition* GetElementPosition() = 0;

        /// \brief 设置定位行为
        /// \param opElementPosition 定位行为
        /// \return void
        virtual void SetElementPosition(OwnerPtr<IElementPosition> opElementPosition) = 0;


#pragma endregion 定位

#pragma region 参数

        /// \brief 获得参数行为接口
        /// \return const IElementParameters* 参数行为接口
        virtual const IElementParameters* GetElementParameters() const = 0;

        /// \brief 获得参数行为接口
        /// \return IElementParameters* 参数行为接口
        virtual IElementParameters* GetElementParameters() = 0;

#pragma endregion 参数

#pragma region 图形表达及视图相关
        /// \brief 获得IElementModelShape行为接口
        /// \return const IElementModelShape* ElementModelShape行为接口
        virtual const IElementModelShape* GetElementModelShape() const = 0;

        /// \brief 获得IElementModelShape行为接口
        /// \return IElementModelShape* ElementModelShape行为接口
        virtual IElementModelShape* GetElementModelShape() = 0;

        /// \brief 获得视图相关组件接口
        /// \return const IElementViewSpecificShapeComponent* 视图相关组件接口
        virtual const IElementViewSpecificShapeComponent* GetViewSpecificShapeComponent() const = 0;

        /// \brief 获得视图相关组件接口
        /// \return IElementViewSpecificShapeComponent* 视图相关组件接口
        virtual IElementViewSpecificShapeComponent* GetViewSpecificShapeComponentFW() = 0;

        /// \brief 设置视图相关组件接口
        /// \param opElementViewSpecificShapeComponent 视图相关组件
        virtual void SetViewSpecificShapeComponent(
            OwnerPtr<IElementViewSpecificShapeComponent> opElementViewSpecificShapeComponent) = 0;

        /// \brief 设置视图相关组件接口
        /// \param opElementViewSpecificShapeComponent 视图相关组件
        /// \param moduleGroupGuid 自定义数据所属模块组
        virtual void SetViewSpecificShapeComponent(
            OwnerPtr<IElementViewSpecificShapeComponent> opElementViewSpecificShapeComponent, const Guid& moduleGroupGuid) = 0;

        /// \brief 获取图形节点上重载的样式和材质
        /// \return 图形节点样式和材质重载组件
        virtual const IGraphicsNodeStyleAndMaterialOverride* GetShapeGraphicsNodeStyleAndMaterialOverrideComponent() const = 0;

        /// \brief 获取图形节点上重载的样式和材质
        /// \return 图形节点样式和材质重载组件
        virtual IGraphicsNodeStyleAndMaterialOverride* GetShapeGraphicsNodeStyleAndMaterialOverrideComponentFW() = 0;

#pragma endregion 图形表达及视图相关

#pragma region 对象间关系

        /// \brief 获取几何关系组件(如连接、打断、扣减等关系)
        /// \return const IGeometryRelationshipComponent* 几何关系组件
        virtual const IGeometryRelationshipComponent* GetGeometryRelationshipComponent() const = 0;

        /// \brief 获取几何关系组件(如连接、打断、扣减等关系)
        /// \return const IGeometryRelationshipComponent* 几何关系组件
        virtual  IGeometryRelationshipComponent* GetGeometryRelationshipComponent()  = 0;

#pragma endregion 对象间关系

#pragma region 外部数据
        /// \brief 获得外部数据接口
        /// \return const IExternalDataComponent * 外部数据接口
        virtual const IExternalDataComponent* GetExternalDataComponent() const = 0;

        /// \brief 获得外部数据接口
        /// \return IExternalDataComponent * 外部数据接口
        virtual IExternalDataComponent* GetExternalDataComponent() = 0;
#pragma endregion 外部数据

#pragma region 属性和标签
        /// \brief 获得元素属性接口
        /// \return const IElementAttributes * 元素属性接口
        virtual const IElementAttributes* GetAttributes() const = 0;

        /// \brief 获得元素属性接口
        /// \return IElementAttributes * 元素属性接口
        virtual IElementAttributes* GetAttributes() = 0;

        /// \brief 获取标签组件
        /// \return 元素的标签组件
        virtual const IElementTags * GetTags() const = 0;

        /// \brief 获取标签组件
        /// \return 元素的标签组件
        virtual IElementTags * GetTags() = 0;
#pragma endregion 属性和标签

#pragma region 成组
        /// \brief 设置成组组件
        /// \param opGroupComponent 成组组件
        /// \return bool
        virtual bool SetGroupComponent(OwnerPtr<IGroupComponent> opGroupComponent) = 0;

        /// \brief 获得成组组件
        /// \return IGroupComponent * 成组组件
        /// \see IGroupComponent
        virtual IGroupComponent * GetGroupComponent() = 0;

        /// \brief 获得成组组件
        /// \return const IGroupComponent * 报告拷贝策略组件
        /// \see IGroupComponent
        virtual const IGroupComponent * GetGroupComponent() const = 0;
#pragma endregion 成组

#pragma region 其他  

        virtual const IElementModelingOperations* GetModelingOperations() const = 0;
        virtual IElementModelingOperations* GetModelingOperationsFW() = 0;

        virtual const ICommandBehavior* GetCommandBehavior() const = 0;
        virtual ICommandBehavior* GetCommandBehaviorFW() = 0;

        virtual const IElementConstraintBehavior* GetElementConstraintBehavior() const = 0;
        virtual IElementConstraintBehavior* GetElementConstraintBehaviorFW() = 0;

#pragma endregion 其他

#pragma region 私有和受保护的方法
        friend class ElementImpl;
        friend class ElementBasicInformation;
        friend class ModelView;

#pragma endregion 私有和受保护的方法
        
#pragma region 准备删除
    public:
        // 【问题】存在这样的调用：GetAllElements<IElement>()，函数体里实现的时候会用到T::GetStaticClassSchema()。
        static gcmp::NdbClassSchema* GetStaticClassSchema();// 放入Ndb宏里
        // 暂时先加上这个接口，等到ElementImpl被拆分完成之后，将该接口删除。
        virtual ElementImpl* GetElementImpl() = 0;
        virtual const ElementImpl* GetElementImpl() const = 0;

        virtual bool FinishEditing() = 0;

#pragma endregion 准备删除
     public:
         /// \brief 析构函数
         virtual ~IElement();

     public:
             /// \brief 获取Implementation Uid
             ///
             /// \return UniIdentity 返回ImplementationUid
         static UniIdentity GetImplementationUid();
    };

}// namespace gcmp
